﻿using System;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel;
using System.Collections.Generic;

namespace SpeadFrm.Web.Mvc
{
    public class ExcelResult<T> : ActionResult where T : new()
    {
        public List<T> Source { get; set; }
        public string FileName { get; set; }
        public List<string> HeadList { get; set; }

        public ExcelResult(List<T> source, List<string> headList, string fileName)
        {
            Source = source;
            FileName = string.IsNullOrEmpty(fileName) ? DateTime.Now.ToString("yyyyMMddHHmmss") : fileName;
            HeadList = headList;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (Source == null || Source.Count == 0)
            {
                new EmptyResult().ExecuteResult(context);
                return;
            }

            SetResponse(context);
        }

        private void SetResponse(ControllerContext context)
        {
            var sb = ConvertSource();
            context.HttpContext.Response.Clear();
            context.HttpContext.Response.ClearContent();
            context.HttpContext.Response.Buffer = true;
            context.HttpContext.Response.Charset = "utf-8";
            context.HttpContext.Response.ContentEncoding = Encoding.Default;
            context.HttpContext.Response.ContentType = "application/ms-excel";
            context.HttpContext.Response.AddHeader("Content-Disposition", "attachment;filename=" + FileName + ".xls");
            context.HttpContext.Response.Write(sb);
            context.HttpContext.Response.End();
        }

        private StringBuilder ConvertSource()
        {
            var sb = new StringBuilder();
            AddTableHead(sb);
            AddTableBody(sb);

            return sb;
        }

        private void AddTableBody(StringBuilder sb)
        {
            if (Source == null || Source.Count == 0)
                return;

            var properties = FindProperties();
            if (properties == null || properties.Count == 0)
                return;

            foreach (var t in Source)
            {
                for (int j = 0; j < properties.Count; j++)
                {
                    var sign = properties.Count - 1 == j ? "\n" : "\t";
                    var obj = properties[j].GetValue(t);
                    obj = obj == null ? string.Empty : obj.ToString();
                    sb.Append(obj + sign);
                }
            }
        }

        private void AddTableHead(StringBuilder sb)
        {
            if (Source == null || Source.Count == 0) return;

            var properties = FindProperties();
            if (properties == null || properties.Count == 0) return;

            if (HeadList == null || HeadList.Count == 0)
            {
                for (int i = 0; i < properties.Count; i++)
                {
                    var sign = properties.Count - 1 == i ? "\n" : "\t";
                    if(!string.IsNullOrEmpty(properties[i].Description))
                        sb.Append(properties[i].Description + sign);
                    else
                        sb.Append(properties[i].Name + sign);
                }
            }
            else
            {
                for (int i = 0; i < HeadList.Count; i++)
                {
                    var sign = HeadList.Count - 1 == i ? "\n" : "\t";
                    sb.Append(HeadList[i] + sign);
                }
            }
        }

        private static PropertyDescriptorCollection FindProperties()
        {
            return TypeDescriptor.GetProperties(typeof(T));
        }
    }

}
